package com.github.beihaifeiwu.myspring.http.feign;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.beihaifeiwu.myspring.core.SpringBeans;
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.Retryer;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.form.FormEncoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.okhttp.OkHttpClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.List;

/**
 * Created by liupin on 2017/9/5.
 */
@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties(FeignProperties.class)
@Import(FeignClientsRegistrar.class)
public class FeignClientConfiguration {

    @Autowired
    @FeignGlobalInterceptor
    private ObjectProvider<List<RequestInterceptor>> interceptors;

    @Autowired
    @FeignGlobalConfigurer
    private ObjectProvider<List<FeignBuilderConfigurer>> configurers;

    private final FeignProperties properties;

    @Autowired
    public FeignClientConfiguration(FeignProperties properties) {
        this.properties = properties;
    }

    @Bean(name = FeignBuilderFactoryBean.BEAN_NAME)
    @ConditionalOnMissingBean
    public FeignBuilderFactoryBean feignBuilder() {
        List<RequestInterceptor> interceptors = SpringBeans.getBeans(this.interceptors);
        List<FeignBuilderConfigurer> configurers = SpringBeans.getBeans(this.configurers);
        return new FeignBuilderFactoryBean(properties, interceptors, configurers);
    }

    @Bean
    @ConditionalOnMissingBean
    public Retryer retryer() {
        FeignProperties.Retry retry = properties.getRetry();
        if (retry.isEnabled()) {
            return new Retryer.Default(retry.getPeriod(), retry.getMaxPeriod(), retry.getMaxAttempts());
        }
        return Retryer.NEVER_RETRY;
    }

    @Configuration
    @ConditionalOnClass({ JacksonDecoder.class, FormEncoder.class })
    protected static class JacksonFeignConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public Decoder feignDecoder(ObjectMapper objectMapper) {
            return new JacksonDecoder(objectMapper);
        }

        @Bean
        @ConditionalOnMissingBean
        public Encoder feignEncoder(ObjectMapper objectMapper) {
            JacksonEncoder delegate = new JacksonEncoder(objectMapper);
            return new SpringFormEncoder(delegate);
        }

    }

    @Configuration
    @ConditionalOnClass(OkHttpClient.class)
    protected static class FeignHttpClientConfiguration {

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient(ObjectProvider<okhttp3.OkHttpClient> provider) {
            okhttp3.OkHttpClient okHttpClient = provider.getIfAvailable();
            if (okHttpClient != null) {
                return new OkHttpClient(okHttpClient);
            }
            return new OkHttpClient();
        }

    }

}
